home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 …ember: Reference Library / Dev.CD Dec 94.toast / Technical Documentation / Mac Tech Notes (DocViewer) / ME • Memory / ME10 MultiFinder & _SetGro / ME10 MultiFinder & _SetGro
Encoding:
Text File  |  1994-10-19  |  14.4 KB  |  38 lines  |  [ONLN/HLX2]

  1. ME 10 - MultiFinder and _SetGrowZone
  2. Memory    
  3. Written by:    Andrew Shebanow    June 1989
  4. MultiFinder patches the _SetGrowZone trap, and this patch can cause your program to crash if you attempt to save and restore the grow zone procedure.
  5. MultiFinder gives each application its own heap in which to run.  Because it wants to do some fairly tricky memory management, MultiFinder installs its own grow zone procedure (gzProc) in the application heap, and patches _SetGrowZone to store your application’s gzProc in a temporary variable inside of itself.
  6. A problem arises when you want to allocate some memory without invoking the application’s gzProc.  This can be useful if you are writing a library of routines that does its own internal caching, and you do not want that cache to purge the application’s reserved memory.  Let’s say that to do this, you write a pair of routines, KillGZProc and RestoreGZProc, which look like this:
  7.     #include <Memory.h>
  8.     GrowZoneProcPtr savedGZProc;
  9.     pascal void KillGZProc(void)
  10.     {
  11.         THZ myZone;
  12.         myZone = GetZone();
  13.         /*    since there is no GetGrowZone trap, we have to pull it directly
  14.             from the zone header (Ugh! Very gross!) */
  15.         savedGZProc = myZone->gzProc;
  16.         /* we don't want a grow zone proc */
  17.         SetGrowZone( (GrowZoneProcPtr) nil);
  18.     }
  19.     pascal void RestoreGZProc(void)
  20.     {
  21.         /* set to saved value */
  22.         SetGrowZone(savedGZProc);
  23.     }
  24. Now let’s say that you bracket your call to _NewHandle with these two routines.  When MultiFinder is active, you get the following:
  25. •    When the application starts, you set your gzProc to the routine MyGZProc.  MultiFinder stores the procedure pointer inside of your application’s MultiFinder data area.
  26. •    You call KillGZProc.  The global variable savedGZProc now contains a pointer to MultiFinder’s gzProc, which MultiFinder installed in your zone header before your application started.
  27. •    You do your memory allocation, and your gzProc (MyGZProc) doesn’t get called, just as you intended.
  28. •    You call RestoreGZProc, which stores a pointer to MultiFinder’s gzProc in your application’s MultiFinder data area.
  29. •    The next time you do a memory allocation that causes the gzProc to be called, MultiFinder’s gzProc will be called.  One of the things this gzProc does is to see if there is a valid gzProc stored in your application’s MultiFinder data area.  If there is a valid gzProc, it gets called.  But the gzProc in your application’s MultiFinder data area is MultiFinder’s gzProc, so we go into an infinite loop.  Oops…
  30. The only solution to work around this problem is to avoid reading the value of the gzProc out of the zone header, since it isn’t valid when MultiFinder is active.  (Reading the fields of the zone header is dangerous, compatibility wise as well.)  Your application should only have one grow zone procedure, so you should change your KillGZProc and RestoreGZProc to restore your application’s grow zone procedure directly.  The corrected code would look like the following:
  31.     #include <Memory.h>
  32.     pascal long MyGrowZone(Size cbNeeded);
  33.     pascal void KillGZProc(void)
  34.     {
  35.         /* we don't want a grow zone proc */
  36.         SetGrowZone( (GrowZoneProcPtr) nil);
  37.     }
  38.     pascal void RestoreGZProc(void)
  39.     {
  40.         /* set to my routine */
  41.         SetGrowZone(MyGrowZone);
  42.     }
  43. As you can see, the code is simpler, though not quite as flexible, but at least it won’t throw your machine for a loop.
  44. Further Reference:
  45. •    Inside Macintosh, Volume II, Memory Manager
  46. •    Programmers Guide To MultiFinder (APDA)
  47. •    Technical Note TB 14 — MultiFinder Questions
  48. •    Technical Note OV 17 — MultiFinder Revisited
  49. •    Technical Note OV 11 — The Joy Of Being 32-Bit Clean
  50. hHRˇ ˇˇˇˇRH†Ç
  51. /ZÅ#
  52.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  53. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  54. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  55. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  56. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  57.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  58. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  59. HR.°dONLNdçZ†©(õZ$ME 10 - MultiFinder and _SetGrowZone
  60. °dONLNd%üZÆë*Memory
  61. °dONLNd-∫ZΔè* Written by:°dONLNd9∫¢Δ˝)HAndrew Shebanow°dONLNdI∫ÎΔ(√Π   June 1989°dONLNdS”ZflÃ(‹ZMultiFinder patches the ,
  62. Courier°dONLNdk“Ãfi )r _SetGrowZone°dONLNdw” fl∞)T  trap, and this patch can cause °dONLNdó”∞fl)êyour program to crash°dONLNd≠flZÎr(ËZ;if you attempt to save and restore the grow zone procedure. ˜X˜°dONLNdÈZç*%AMultiFinder gives each application its own heap in which to run. °dONLNd*ç(
  63. ç Because it wants to do some°dONLNdGZŒ(ZCfairly tricky memory management, MultiFinder installs its own grow °dONLNdäŒ(Œzone procedure°dONLNdôZ)^(&Z(°dONLNdö^(à)gzProc°dONLNd†à))*) in the application heap, °dONLNdª)B)| and patches °dONLNd«B(ñ)> _SetGrowZone°dONLNd”ñ))T to store your application’s°dONLNd)Z5Ñ(3ZgzProc°dONLNdˆ*Ñ6=)** in a temporary variable inside of itself.°dONLNd!BZNq(KZ7A problem arises when you want to allocate some memory °dONLNdXBqNú(Kqwithout°dONLNd_BúN)+ invoking the application’s°dONLNd{NZZÑ(XZgzProc°dONLNdÅOÑ[)*.  This can be useful if you °dONLNdûO[)Ç<are writing a library of routines that does its own internal°dONLNd€[Zg(dZUcaching, and you do not want that cache to purge the application’s reserved memory.  °dONLNd0[g(d    Let’s say°dONLNd:hZt((qZ/that to do this, you write a pair of routines, °dONLNdig(sn)Œ
  64. KillGZProc°dONLNdshntÖ)F and °dONLNdxgÖs‡)
  65. RestoreGZProc°dONLNdÖh‡t)[, which °dONLNdçht)'look°dONLNdítZÄÇ(}Z
  66. like this:
  67.     °dONLNdûå~ó›+$#include <Memory.h>°dONLNd≥†~´
  68. *GrowZoneProcPtr savedGZProc;°dONLNd—¥~ø
  69. *pascal void KillGZProc(void)°dONLNdÔæ~…É*
  70. {°dONLNdÛ»¢”Ÿ+$
  71. THZ myZone;°dONLNd‹¢Á*myZone = GetZone();°dONLNdÊ¢Ò¨*
  72. /*°dONLNdÊΔÒ)$?since there is no GetGrowZone trap, we have to pull it directly°dONLNd]Δ˚ò*
  73. *from the zone header (Ugh! Very gross!) */°dONLNdä˙¢3(¢savedGZProc = myZone->gzProc;°dONLNd™¢V*
  74. $/* we don't want a grow zone proc */°dONLNd—¢V*
  75. $SetGrowZone( (GrowZoneProcPtr) nil);°dONLNd˜~#É( ~}°dONLNd˙,~7*pascal void RestoreGZProc(void)°dONLNd6~AÉ*
  76. {°dONLNd@¢K+$
  77. /* set to saved value */°dONLNd:J¢U*
  78. SetGrowZone(savedGZProc);°dONLNdUT~_É(\~}
  79. °dONLNdWkZw∑(tZNow let’s say that °dONLNdjk∑w3)]you bracket your call to °dONLNdÉj3vy)|
  80. _NewHandle°dONLNdçkyw)F with these two routines.  When°dONLNd≠wZÉ*(ÄZ-MultiFinder is active, you get the following: ΩXΩ
  81. *U$ME 10 - MultiFinder and _SetGrowZone(’1) of 2(ÎZMemoryˇ°¿Ù%%DSIDICT:_cv
  82. currentdict /bu known {bu}if
  83. userdict /_cv known not{userdict /_cv 30 dict put}if
  84. _cv begin
  85. /bdf{bind def}bind def
  86. currentscreen/cs exch def/ca exch def/cf exch def
  87. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  88. /ss{//cf //ca //cs setscreen}bdf
  89. /stg{ss setgray}bdf
  90. /strgb{ss setrgbcolor}bdf
  91. /stcmyk{ss cvcmyk}bdf
  92. /min1{dup 0 eq{pop 1}if}bdf
  93. end
  94. currentdict /bn known {bn}if
  95. †ø$HRˇ ˇˇˇˇRH
  96. HR,Times
  97. .+6-Macintosh Technical Notes /4/˘
  98. °dONLNd=HIL+•°dONLNd=UIı)
  99. !When the application starts, you °dONLNd#=ıI")†    set your ,
  100. Courier°dONLNd,<"HL)-gzProc°dONLNd2=LIò)* to the routine °dONLNdB<òH–)LMyGZProc°dONLNdJ=–I‘)8.°dONLNdMIUUB(RU3MultiFinder stores the procedure pointer inside of °dONLNdÄIBU‘)Ìyour application’s MultiFinder°dONLNdüUUaÇ(^U
  101. data area.°dONLNd™bHnL(kH•°dONLNd¨bUnÅ)
  102.     You call °dONLNdµaÅm«),
  103. KillGZProc°dONLNdøb«nœ)F. °dONLNd¡bœn7) The global variable °dONLNd÷a7mÑ)h savedGZProc°dONLNd·bÑn‘)M now contains a°dONLNdÒoU{á(xU pointer to °dONLNd¸oá{⁄)2MultiFinder’s °dONLNd
  104. n⁄z)SgzProc°dONLNdo{i)*, which MultiFinder °dONLNd$oi{‘)einstalled in your zone°dONLNd;{Uá
  105. (ÑU'header before your application started.°dONLNdcàHîL(ëH•°dONLNdeàUîó)
  106. You do your °dONLNdqàóî*)Bmemory allocation, and your °dONLNdçá*ìT)ìgzProc°dONLNdìàTî])* (°dONLNdïá]ìï)    MyGZProc°dONLNdùàïî‘)8
  107. ) doesn’t get°dONLNd´îU†Ÿ(ùUcalled, just as you intended.°dONLNd…°H≠L(™H•°dONLNdÀ°U≠)
  108.     You call °dONLNd‘†¨⁄)*
  109. RestoreGZProc°dONLNd·°⁄≠X)[, which stores a pointer to °dONLNd˝°X≠ù)~MultiFinder’s °dONLNd †ù¨«)EgzProc°dONLNd°«≠‘)* in°dONLNd≠Uπ(∂U)your application’s MultiFinder data area.°dONLNd?∫HΔL(√H•°dONLNdA∫UΔº)
  110. The next time you do °dONLNdV∫ºΔk)g$a memory allocation that causes the °dONLNdzπk≈ï)ØgzProc°dONLNdÄ∫ïΔ‘)* to be called,°dONLNdè«U”ô(–UMultiFinder’s °dONLNdùΔô“√)DgzProc°dONLNd£«√”b)*$ will be called.  One of the things °dONLNd««b”w)üthis °dONLNdÃΔw“°)gzProc°dONLNd“«°”‘)*  does is to°dONLNdfi‘U‡∏(›Usee if there is a valid °dONLNdˆ”∏fl‚)cgzProc°dONLNd¸‘‚‡*)* stored in your °dONLNd ‘*‡‘)H$application’s MultiFinder data area.°dONLNd2·UÌß(ÍUIf there is a valid °dONLNdF‡ßÏ—)RgzProc°dONLNdL·—Ì)*, it gets called.  °dONLNd_·ÌC)KBut the °dONLNdg‡CÏm)'gzProc°dONLNdm·mÌ‘)* in your application’s°dONLNdÑÓU˙¶(˜UMultiFinder data °dONLNdïÓ¶˙)Qarea is MultiFinder’s °dONLNd´Ì˘8)hgzProc°dONLNd±Ó8˙‘)*!, so we go into an infinite loop.°dONLNd‘˙Uz(UOops…°dONLNd⁄6ª(6SThe only solution to work around this problem is to avoid reading the value of the °dONLNd-ªÂ(ªgzProc°dONLNd3¯)* out°dONLNd86+C((6of °dONLNd;C+¯)
  111. ]the zone header, since it isn’t valid when MultiFinder is active.  (Reading the fields of the°dONLNdô+679(467zone header is dangerous, compatibility wise as well.) °dONLNd–+97¯(49& Your application should only have one°dONLNd˜86DÌ(A6#grow zone procedure, so you should °dONLNd8ÌD.)∑ change your °dONLNd&7.Ct)A
  112. KillGZProc°dONLNd08tDè)F and °dONLNd57èCÍ)
  113. RestoreGZProc°dONLNdB8ÍD¯)[ to°dONLNdFD6PÁ(M6Xrestore your application’s grow zone procedure directly.  The corrected code would look °dONLNdûDÁP¯(MÁlike°dONLNd£P6\x(Y6the following:
  114.     °dONLNd≥hZsπ+$#include <Memory.h>°dONLNd»|Zá*&pascal long MyGrowZone(Size cbNeeded);°dONLNdêZõÊ*pascal void KillGZProc(void)°dONLNdöZ•_*
  115. {°dONLNd§~Ø2+$
  116. $/* we don't want a grow zone proc */°dONLNd9Æ~π2*
  117. $SetGrowZone( (GrowZoneProcPtr) nil);°dONLNd_∏Z√_(¿Z}°dONLNdbÃZ◊ı*pascal void RestoreGZProc(void)°dONLNdÉ÷Z·_*
  118. {°dONLNdá‡~ÎÒ+$
  119. /* set to my routine */°dONLNd°Í~ıˆ*
  120. SetGrowZone(MyGrowZone);°dONLNdªÙZˇ_(¸Z}
  121. °dONLNdΩ
  122. 6ñ(6JAs you can see, the code is simpler, though not quite as flexible, but at °dONLNd
  123. ñ¯(ñleast it won’t throw°dONLNd6"´(6your machine for a loop.°dONLNd5F6R†*0Further Reference: R4R˘°dONLNdHSH_L+
  124. •°dONLNdJSZ_´)Inside Macintosh°dONLNdZS´_=)Q, Volume II, Memory Manager°dONLNdv_HkL(hH•°dONLNdx_Zk) Programmers Guide To MultiFinder°dONLNdò_k/)´ (APDA)°dONLNd†kHwL(tH•°dONLNd¢kZw>),Technical Note TB 14 — MultiFinder Questions°dONLNdœwHÉL(ÄH•°dONLNd—wZÉ<),Technical Note OV 17 — MultiFinder Revisited°dONLNd˛ÉHèL(åH•°dONLNdÉZèh)4Technical Note OV 11 — The Joy Of Being 32-Bit Clean Ω4Ω˘
  125. (’62) of 2(’T$ME 10 - MultiFinder and _SetGrowZone+ÇMemoryˇ